package com.zk.schedule.config;

import com.google.gson.Gson;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 配置工具类
 * Created by hh on 9/8/15.
 */
public class ConfUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfUtils.class);

    private static ZkConfig zkConfig; // 保证只有一个zkConfig

    private static Lock lock = new ReentrantLock();

    static {
        load();
    }

    private ConfUtils() {}

    public static ZkConfig refreshConfig() {
        load();
        return loadConfig();
    }

    public static ZkConfig loadConfig() {
        return zkConfig;
    }

    private static void load() {
        lock.lock();
        try {
            zkConfig = loadFromClassPath();
            LOGGER.info("加载配置信息：{}", new Gson().toJson(zkConfig));
            if (!validate(zkConfig)) {
                throw new RuntimeException("配置文件错误");
            }
        } finally {
            lock.unlock();
        }
    }

    private static boolean validate(ZkConfig config) {
        return !config.isStart() || !StringUtils.isBlank(config.getCxnString());
    }

    private static ZkConfig loadFromClassPath() {
        try {
            Properties properties = PropertiesLoaderUtils.loadProperties(new ClassPathResource(ZkConfig.Constant.CONF_PATH));
            return fillProperties(properties);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }
        return null;
    }

    private static ZkConfig fillProperties(Properties properties) {
        if (properties != null) {
            String prePath = StringUtils.trimToEmpty(properties.getProperty(ZkConfig.Constant.PRE_PATH));
            if(StringUtils.startsWith(prePath, "/")) {
                prePath = StringUtils.substring(prePath, 1);
            }
            if(StringUtils.isBlank(prePath)) {
                prePath = getProjectName();
            }
            zkConfig = new ZkConfig();
            zkConfig.setCxnString(StringUtils.trimToNull(properties.getProperty(ZkConfig.Constant.CXN_STRING)));
            zkConfig.setRunInAll(BooleanUtils.toBoolean(StringUtils.trimToNull(properties.getProperty(ZkConfig.Constant.RUN_IN_ALL, "false"))));
            zkConfig.setRootPath("/zk/schedule/" + prePath);
            zkConfig.setAutoRegisterTask(BooleanUtils.toBoolean(StringUtils.trimToNull(properties.getProperty(ZkConfig.Constant.AUTO_REGISTER_TASK, "true"))));
            zkConfig.setStart(BooleanUtils.toBoolean(StringUtils.trimToNull(properties.getProperty(ZkConfig.Constant.START, "true"))));
            zkConfig.setIgnoreTaskMap(getIgnoreTask(properties));
        }
        return zkConfig;
    }

    /**
     * 获取应用所在的user.dir
     *
     * @return user.dir
     */
    private static String getProjectName() {

        ClassLoader classLoader = ConfUtils.class.getClassLoader();
        String projectName;
        if (classLoader != null && classLoader.getResource(StringUtils.EMPTY) != null) {
            projectName = classLoader.getResource(StringUtils.EMPTY).toString();
        } else {
            projectName = ConfUtils.class.getResource(StringUtils.EMPTY).toString();
        }
        LOGGER.info(projectName);
        if (projectName.contains(File.separator + "WEB-INF") || projectName.contains("/WEB-INF")) {// tomcat应用
            //modified by huanghua 2014-10-31 10:07:11
            //projectName = projectName.replaceAll(File.separator + "WEB-INF.*", "");
            //修复windows获取不到projectName的问题.
            projectName = StringUtils.substringBefore(projectName, "/WEB-INF");
            projectName = StringUtils.substringAfterLast(projectName, "/");
        } else if (projectName.contains("jar:file:") || projectName.contains("file:")) {// 非tomcat应用
            if (projectName.contains("/target")) {
                projectName = StringUtils.substringBeforeLast(projectName, "/target");
                projectName = StringUtils.substringAfterLast(projectName, "/");
            } else if (projectName.contains("/build")) {
                projectName = StringUtils.substringBeforeLast(projectName, "/build");
                projectName = StringUtils.substringAfterLast(projectName, "/");
            } else {
                projectName = StringUtils.substringBeforeLast(projectName, "/lib");
                projectName = StringUtils.substringAfterLast(projectName, "/");
            }
        } else {
            projectName = System.getProperty("user.dir");
        }
        LOGGER.info("app name:{}", projectName);
        return projectName;
    }

    /**
     * 获取需要停止的任务
     * @param properties 配置
     * @return task:isAllNode
     */
    private static Map<String, Boolean> getIgnoreTask(Properties properties) {
        Map<String, Boolean> map = new HashMap<>();
        String it = properties.getProperty(ZkConfig.Constant.IGNORE_TASK);

        if(StringUtils.isBlank(it)) {
            return map;
        }
        LOGGER.debug("ignore task config string:{}", it);
        String[] tasks = StringUtils.split(it, ",");
        for (String s : tasks) {
            String[] c = StringUtils.split(s, "#");
            if(c == null || c.length < 2) {
                LOGGER.warn("ignore task config illegal item:{}", s);
                continue;
            }
            String taskName = c[0] + "#" + c[1];
            boolean isAllNode = true;
            if(c.length > 2) {
                isAllNode = BooleanUtils.toBoolean(StringUtils.trimToNull(c[2]));
            }
            map.put(taskName, isAllNode);
        }
        return map;
    }

}
